#include "inc/my_include.h"
#include "inc/zcd_timer.h"
#include "inc/my_fifo.h"

inline int GetDaChCount(int daEn);
U16* CreateSinWave(int groupFreq, int waveFreq, int chCount, int* codeCnt);
U16* CreateRectWave(int chCount, int* codeCnt);
void ExitExe(int i);

int daEn = 0x3; //使能2个通道的DA
int rangeInx = 0; //10V
int bc1s = 0; //1S的数据字节个数，在main函数中根据采集频率和通道号计算得出。
int fd; //设备描述符
unsigned short daCode[2048];
U16* waveBuf = 0;

int WriteFifoToFull( U16* waveBuf, int codeCnt, int* writeCnt, int timeoutMS )
{//由于有的时候读回来可写数据不准确，因此不使用这个函数
	ZcdTimer tv;
	ZcdTimer_Init(&tv); //用于看程序运行了多长时间
	int error = 0;
	int tempWriteCnt = 0;
	while (!error)
	{
		U16 canWriteCnt = 0;
		I64 tUS = ZcdTimer_GetTimeInterval(&tv);
		if (tUS > 1000 * timeoutMS)
		{
			//如果超时则退出
			EM9106_DaHFifoCanWriteCnt(fd, &canWriteCnt);
			printf( "%s:canWriteCnt:%d\n", __FUNCTION__, canWriteCnt );
			printf("time out!\n");
			error = -2;
			break;
		}
		EM9106_DaHFifoCanWriteCnt(fd, &canWriteCnt);

		if (canWriteCnt >= codeCnt*2 )
		{
//			printf( "%s:canWriteCnt:%d,codeCnt:%d\n", __FUNCTION__, canWriteCnt, codeCnt );
			EM9106_DaWriteHFifo(fd, waveBuf, codeCnt);
			tempWriteCnt += codeCnt;
//			printf( "canWriteCnt >= codeCnt*2:tempWriteCnt:%d\n", tempWriteCnt);
		}
		else
		{//最后剩余空间不足两个波形则不再写入,因为写满会导致FIFO可写数量不准确
			break;
		}
	}
	if( writeCnt )
		*writeCnt = tempWriteCnt;
//	printf( "WriteFifoToFull:tempWriteCnt:%d\n", tempWriteCnt);
	return error;
}
//写FIFO到半满以上
int WriteFifoOverH( U16* waveBuf, int codeCnt, int* writeCnt, int timeoutMS )
{
	ZcdTimer tv;
	ZcdTimer_Init(&tv); //用于看程序运行了多长时间
	int error = 0;
	int tempWriteCnt = 0;
	while (!error)
	{
		U16 canWriteCnt = 0;
		I64 tUS = ZcdTimer_GetTimeInterval(&tv);
		if (tUS > 1000 * timeoutMS)
		{
			//如果超时则退出
			EM9106_DaHFifoCanWriteCnt(fd, &canWriteCnt);
			U16 fCtrl = EM9118_Inw( fd, ADDR_DACTRL );
			printf( "%s:canWriteCnt:%d,ctrl:%x\n", __FUNCTION__, canWriteCnt, fCtrl );
			printf("time out!\n");
			error = -2;
			break;
		}
		U16 fCtrl = EM9118_Inw( fd, ADDR_DACTRL );
		if (!(fCtrl & 0x2000)) //半满有效则不需要往里面写
		{
			U16 canReadCnt = EM9118_Inw( fd, ADDR_DAFIFOCNT );
//			printf( "%s:!(fCtrl & 0x2000),fCtrl:%x canReadCnt:%u\n", __FUNCTION__, fCtrl, canReadCnt );
			//usleep(10000);
			break;
		}
		else if (!(fCtrl & 0x4000)) //空
		{
			U16 canReadCnt = EM9118_Inw( fd, ADDR_DAFIFOCNT);
			printf("%s:!(fCtrl & 0x4000),fCtrl:%x canReadCnt:%u\n",
					__FUNCTION__, fCtrl, canReadCnt);
		}
		int groupCnt = 1024 / codeCnt;//取整
		if( groupCnt == 0 )
		{
			printf( "groupCnt == 0!\n" );
			error = -3;
			break;
		}

		int i = 0;
		for( i = 0; i < groupCnt; ++i )
		{
//			printf( "%s:canWriteCnt:%d,codeCnt:%d\n", __FUNCTION__, canWriteCnt, codeCnt );
			EM9106_DaWriteHFifo(fd, waveBuf, codeCnt);
			tempWriteCnt += codeCnt;
//			printf( "canWriteCnt >= codeCnt*2:tempWriteCnt:%d\n", tempWriteCnt);
		}
		fCtrl = EM9118_Inw( fd, ADDR_DACTRL );
		U16 canReadCnt = EM9118_Inw(fd, ADDR_DAFIFOCNT);
		printf("%s:!(fCtrl & 0x4000),fCtrl:%x canReadCnt:%u\n", __FUNCTION__,
				fCtrl, canReadCnt);
	}
	if( writeCnt )
		*writeCnt = tempWriteCnt;
//	printf( "WriteFifoToFull:tempWriteCnt:%d\n", tempWriteCnt);
	return error;
}

int main(int argc, char *argv[])
{
//	signal(SIGINT, ExitExe); //接收ctrl-c信号，主要是调试用

	fd = EM9118_Init();
	//初始化内核缓冲区，内核缓冲区大小固定为819200
	int daChCount = GetDaChCount(daEn);
	//清空硬件FIFO
	EM9106_DaHFifoClear(fd);
	//使能中断，后面那个5不用考虑
	EM9118_IRQEnable(fd, 5);
	//设置采集范围
	EM9106_DaSetRange(fd, 0);
	//设置采集频率
	printf( "frequency:" );
	int groupFreq;
	scanf( "%d", &groupFreq );
	int groupFreqDiv = 36000000 / groupFreq; //求出分频系数
	EM9106_DaSetFreqDiv(fd, groupFreqDiv);
	//设置通道使能
	EM9106_DaSetEnCh(fd, daEn);
	int codeCnt;
	waveBuf = CreateRectWave(daChCount, &codeCnt);
	//写FIFO到满
	int writeCnt = 0;
	int error = WriteFifoOverH( waveBuf, codeCnt, &writeCnt, 1000 );
	F64 allCnt = 0;//writeCnt;
	U16 canWriteCnt = 0;
	EM9106_DaHFifoCanWriteCnt( fd, &canWriteCnt );
	printf( "canWriteCnt:%d\n", canWriteCnt );
	ZcdTimer tv;
	ZcdTimer_Init(&tv);
	//启动输出
	if( !error )
		EM9106_DaStart(fd);
	//计算每秒钟需要多少字节数
	I64 oldUS = ZcdTimer_GetTimeInterval(&tv);
	while (!error )
	{
		//写FIFO到满
		int error = WriteFifoOverH(waveBuf, codeCnt, &writeCnt, 1000);
		if( writeCnt > 0 )
		{
			allCnt += writeCnt;
			I64 tUS = ZcdTimer_GetTimeInterval(&tv);
			if( tUS - oldUS > 1000000 )
			{
				F64 cntPerS = allCnt / (tUS / 1000000.0);
				oldUS = tUS;
				printf("writeCnt:%d, cntPerS:%0.0f \n", writeCnt, cntPerS);
			}
			if( writeCnt > 2000 )
				printf("writeCnt :%d!\n", writeCnt );
		}
	}

	ExitExe( 0 );

	return 0;
}

//接收ctrl-c信号，主要是调试用
void ExitExe(int i)
{
	printf("Press Enter to exit \n");
	//停止DA输出
	EM9106_DaStop(fd);
	if( waveBuf )
		free( waveBuf );
	waveBuf = 0;
	getchar();
	exit(0);
}

int GetDaChCount(int daEn)
{ //本函数得到所有进入fifo的通道数量，以16位整型为一个通道
	int daChCnt = 0;
	int i = 0;
	for (i = 0; i < DA_CH_COUNT; ++i)
	{
		if ((daEn >> i) & 1)
			++daChCnt;
	}
	return daChCnt;
}

/*U16* CreateSinWave(int groupFreq, int waveFreq, int chCount, int* codeCnt)
{
	//一个周期有多少个数据
	int waveCnt = groupFreq / waveFreq;
	if (waveCnt < 10)
	{ //一个周期如果小于10个点，波形会比较难看
		printf("waveCnt < 10!\n");
		return 0;
	}
	else if (waveCnt * chCount > 1024)
	{ //一个周期如果大于1024，往fifo里面写的时候程序会比较复杂，所以限制在1024以下
		printf("waveCnt * chCount > 1024\n");
		return 0;
	}
	U16* waveBuf = malloc(waveCnt * chCount * sizeof(U16));
	if (!waveBuf)
	{
		printf("waveBuf malloc fails\n");
		return 0;
	}
	//正弦波，相邻通道相位差为90°
	int codeInx = 0;
	int i;
	for ( i = 0; i < waveCnt; ++i)
	{
		int j;
		for ( j = 0; j < chCount; ++j)
		{
			F64 para = 2 * 3.1415926 * i / waveCnt;
			if (j % 2)
				waveBuf[codeInx++] = sin(para);
			else
				waveBuf[codeInx++] = cos(para);
		}
	}
	*codeCnt = codeInx;
	return waveBuf;
}*/

//本函数创建方波，频率为DA输出频率的一半
U16* CreateRectWave(int chCount, int* codeCnt)
{
	//每个通道产生128个数据
	int waveCnt = 128;
	U16* waveBuf = malloc(waveCnt * chCount * sizeof(U16));
	if (!waveBuf)
	{
		printf("waveBuf malloc fails\n");
		return 0;
	}
	//相邻数据为最大值和最小值，这样就可以产生方波。相邻通道相位是180°
	int codeInx = 0;
	int i;
	for ( i = 0; i < waveCnt; ++i)
	{
		int j;
		for (j = 0; j < chCount; ++j)
		{
			if (j % 2)
				waveBuf[codeInx++] = (i % 2) * 65535;
			else
				waveBuf[codeInx++] = ((i+1) % 2) * 65535;
			printf( "%d ", waveBuf[codeInx-1] );
		}
	}
	printf( "\n" );
	*codeCnt = codeInx;
	return waveBuf;
}
